package com.ywgt.single;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.TimeUnit;

public class LazyMan {

    private static boolean flag=false;//设置信号量，对象第一次创建成功则后续直接抛异常

    private LazyMan() {
        synchronized (LazyMan.class) { //防止多个线程进入，需要加锁
            if (flag == false) {
                flag = true;
            } else {
                throw new RuntimeException("不要使用反射来搞破坏");
            }
        /*synchronized (LazyMan.class) {
            while (lazyMan != null) {    //如果不是用getInstance()方法创建对象，则lazyMan永远是null，使用反射机制可以进行构对象造
                throw new RuntimeException("不要使用反射来搞破坏");
            }
        }*/
            System.out.println(Thread.currentThread().getName() + "ok");
        }
    }
    private volatile static LazyMan lazyMan;

    public static LazyMan getInstance() {
        if (lazyMan == null) {  //双重检测模式
            synchronized (LazyMan.class) {
                if (lazyMan == null) {
                    lazyMan = new LazyMan();//非原子性操作 1.分配内存空间 2.执行构造方法 3.将指向空间  可能存在指令重排，避免指令重排
                }
            }
        }
        return lazyMan;
    }
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(()->{
                System.out.println(LazyMan.getInstance());
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            },String.valueOf(i)).start();
        }
    }
}

class Reflect{
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
        Constructor<LazyMan> constructor = LazyMan.class.getDeclaredConstructor(null);
        Field flag = LazyMan.class.getDeclaredField("flag");
        flag.setAccessible(true);
        constructor.setAccessible(true);
        LazyMan instance = constructor.newInstance();//第一次使用构造器直接可以创建成功
        System.out.println(instance);
        flag.set(instance,false);
        LazyMan instance2 = constructor.newInstance();
        System.out.println(instance2);
        flag.set(instance,false);
        LazyMan instance3 = constructor.newInstance();
        System.out.println(instance3);
    }

}
